package com.macro.mall.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.github.pagehelper.PageHelper;
import com.macro.mall.common.api.CommonResult;
import com.macro.mall.common.util.ExceptionUtils;
import com.macro.mall.dao.*;
import com.macro.mall.dto.PmsProductParam;
import com.macro.mall.model.PmsProductQueryParam;
import com.macro.mall.dto.PmsProductResult;
import com.macro.mall.mapper.*;
import com.macro.mall.model.*;
import com.macro.mall.operating.starter.annotation.LogRecord;
import com.macro.mall.service.PmsProductService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

/**
 * 商品管理Service实现类
 * Created by macro on 2018/4/26.
 */
@Service
public class PmsProductServiceImpl implements PmsProductService {
    private static final Logger LOGGER = LoggerFactory.getLogger(PmsProductServiceImpl.class);
    @Autowired
    private PmsProductMapper productMapper;
    @Autowired
    private PmsMemberPriceDao memberPriceDao;
    @Autowired
    private PmsMemberPriceMapper memberPriceMapper;
    @Autowired
    private PmsProductLadderDao productLadderDao;
    @Autowired
    private PmsProductLadderMapper productLadderMapper;
    @Autowired
    private PmsProductFullReductionDao productFullReductionDao;
    @Autowired
    private PmsProductFullReductionMapper productFullReductionMapper;
    @Autowired
    private PmsSkuStockDao skuStockDao;
    @Autowired
    private PmsSkuStockMapper skuStockMapper;
    @Autowired
    private PmsProductAttributeValueDao productAttributeValueDao;
    @Autowired
    private PmsProductAttributeValueMapper productAttributeValueMapper;
    @Autowired
    private CmsSubjectProductRelationDao subjectProductRelationDao;
    @Autowired
    private CmsSubjectProductRelationMapper subjectProductRelationMapper;
    @Autowired
    private CmsPrefrenceAreaProductRelationDao prefrenceAreaProductRelationDao;
    @Autowired
    private CmsPrefrenceAreaProductRelationMapper prefrenceAreaProductRelationMapper;
    @Autowired
    private PmsProductDao productDao;
    @Autowired
    private PmsProductVertifyRecordDao productVertifyRecordDao;

    @Override
    public int create(PmsProductParam productParam) {
        int count;
        //创建商品
        PmsProduct product = productParam;
        product.setId(null);
        productMapper.insertSelective(product);
        //根据促销类型设置价格：会员价格、阶梯价格、满减价格
        Long productId = product.getId();
        //会员价格
        relateAndInsertList(memberPriceDao, productParam.getMemberPriceList(), productId);
        //阶梯价格
        relateAndInsertList(productLadderDao, productParam.getProductLadderList(), productId);
        //满减价格
        relateAndInsertList(productFullReductionDao, productParam.getProductFullReductionList(), productId);
        //处理sku的编码
        handleSkuStockCode(productParam.getSkuStockList(), productId);
        //添加sku库存信息
        relateAndInsertList(skuStockDao, productParam.getSkuStockList(), productId);
        //添加商品参数,添加自定义商品规格
        relateAndInsertList(productAttributeValueDao, productParam.getProductAttributeValueList(), productId);
        //关联专题
        relateAndInsertList(subjectProductRelationDao, productParam.getSubjectProductRelationList(), productId);
        //关联优选
        relateAndInsertList(prefrenceAreaProductRelationDao, productParam.getPrefrenceAreaProductRelationList(), productId);
        count = 1;
        return count;
    }

    private void handleSkuStockCode(List<PmsSkuStock> skuStockList, Long productId) {
        if (CollectionUtils.isEmpty(skuStockList)) return;
        for (int i = 0; i < skuStockList.size(); i++) {
            PmsSkuStock skuStock = skuStockList.get(i);
            if (StringUtils.isEmpty(skuStock.getSkuCode())) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
                StringBuilder sb = new StringBuilder();
                //日期
                sb.append(sdf.format(new Date()));
                //四位商品id
                sb.append(String.format("%04d", productId));
                //三位索引id
                sb.append(String.format("%03d", i + 1));
                skuStock.setSkuCode(sb.toString());
            }
        }
    }

    @Override
    public PmsProductResult getUpdateInfo(Long id) {
        return productDao.getUpdateInfo(id);
    }

    @Override
    public int update(Long id, PmsProductParam productParamOld,PmsProductParam productParamNew) {
        int count;
        //更新商品信息
        PmsProduct product = productParamNew;
        product.setId(id);
        productMapper.updateByPrimaryKeySelective(product);
        //会员价格
        List<PmsMemberPrice> memberPriceListOld = productParamOld.getMemberPriceList();
        List<PmsMemberPrice> memberPriceListNew =  productParamNew.getMemberPriceList();

        List<PmsMemberPrice> memberPriceListInsert = new ArrayList<>();
        List<PmsMemberPrice> memberPriceListUpdate = new ArrayList<>();
        List<String> memberPriceListDelete = new ArrayList<>();

        for (PmsMemberPrice pmsMemberPriceValue : memberPriceListNew) {
            if (pmsMemberPriceValue.getId() == null) {
                memberPriceListInsert.add(pmsMemberPriceValue);
            } else {
                memberPriceListUpdate.add(pmsMemberPriceValue);

            }
        }

        for (PmsMemberPrice pmsMemberPrice : memberPriceListOld) {
            if (memberPriceListNew.stream().noneMatch(item -> pmsMemberPrice.getId().equals(item.getId()))){
                memberPriceListDelete.add(pmsMemberPrice.getId());
            }
        }
        relateAndInsertList(memberPriceDao,memberPriceListInsert, id);
        relateAndUpdateList(memberPriceDao, memberPriceListUpdate);
        relateAndDeleteList(memberPriceDao,memberPriceListDelete);

        //阶梯价格
        List<PmsProductLadder> productLadderListOld = productParamOld.getProductLadderList();
        List<PmsProductLadder> productLadderListNew =  productParamNew.getProductLadderList();

        List<PmsProductLadder> productLadderListInsert = new ArrayList<>();
        List<PmsProductLadder> productLadderListUpdate = new ArrayList<>();
        List<String> productLadderListDelete = new ArrayList<>();

        for (PmsProductLadder productLadderValue : productLadderListNew) {
            if (productLadderValue.getId() == null) {
                productLadderListInsert.add(productLadderValue);
            }else {
                productLadderListUpdate.add(productLadderValue);

            }
        }

        for (PmsProductLadder pmsProductLadder : productLadderListOld) {
            if (productLadderListNew.stream().noneMatch(item -> pmsProductLadder.getId().equals(item.getId()))){
                productLadderListDelete.add(pmsProductLadder.getId());
            }
        }
        relateAndInsertList(productLadderDao,productLadderListInsert, id);
        relateAndUpdateList(productLadderDao, productLadderListUpdate);
        relateAndDeleteList(productLadderDao,productLadderListDelete);

        //满减价格
        List<PmsProductFullReduction> productFullReductionListOld = productParamOld.getProductFullReductionList();
        List<PmsProductFullReduction> productFullReductionListNew =  productParamNew.getProductFullReductionList();

        List<PmsProductFullReduction> productFullReductionListInsert = new ArrayList<>();
        List<PmsProductFullReduction> productFullReductionListUpdate = new ArrayList<>();
        List<String> productFullReductionListDelete = new ArrayList<>();

        for (PmsProductFullReduction productFullReductionValue : productFullReductionListNew) {
            if (productFullReductionValue.getId() == null) {
                productFullReductionListInsert.add(productFullReductionValue);
            }else {
                productFullReductionListUpdate.add(productFullReductionValue);

            }
        }
        for (PmsProductFullReduction pmsProductFullReduction : productFullReductionListOld) {
            if (productFullReductionListNew.stream().noneMatch(item -> pmsProductFullReduction.getId().equals(item.getId()))){
                productFullReductionListDelete.add(pmsProductFullReduction.getId());
            }
        }
        relateAndInsertList(productFullReductionDao,productFullReductionListInsert, id);
        relateAndUpdateList(productFullReductionDao, productFullReductionListUpdate);
        relateAndDeleteList(productFullReductionDao,productFullReductionListDelete);

        //修改sku库存信息
        List<PmsSkuStock> skuStockListOld = productParamOld.getSkuStockList();
        List<PmsSkuStock> skuStockListNew =  productParamNew.getSkuStockList();

        List<PmsSkuStock> skuStockListInsert = new ArrayList<>();
        List<PmsSkuStock> skuStockListUpdate = new ArrayList<>();
        List<String> skuStockListDelete = new ArrayList<>();

        for (PmsSkuStock skuStockValue : skuStockListNew) {
            if (skuStockValue.getId() == null) {

                skuStockListInsert.add(skuStockValue);
            } else {
                skuStockListUpdate.add(skuStockValue);

            }
        }

        for (PmsSkuStock skuStockValue : skuStockListOld) {
             if (skuStockListNew.stream().noneMatch(item -> skuStockValue.getId().equals(item.getId()))){
                skuStockListDelete.add(skuStockValue.getId());
            }
        }
        handleSkuStockCode(skuStockListInsert, id);

        relateAndInsertList(skuStockDao,skuStockListInsert, id);
        relateAndUpdateList(skuStockDao, skuStockListUpdate);
        relateAndDeleteList(skuStockDao,skuStockListDelete);

        //修改商品参数,添加自定义商品规格
        List<PmsProductAttributeValue> productAttributeValueListOld = productParamOld.getProductAttributeValueList();
        List<PmsProductAttributeValue> productAttributeValueListNew =  productParamNew.getProductAttributeValueList();

        List<PmsProductAttributeValue> productAttributeValueListInsert = new ArrayList<>();
        List<PmsProductAttributeValue> productAttributeValueListUpdate = new ArrayList<>();
        List<String> productAttributeValueListDelete = new ArrayList<>();

        for (PmsProductAttributeValue pmsProductAttributeValue : productAttributeValueListNew) {
            if (pmsProductAttributeValue.getId() == null) {
                productAttributeValueListInsert.add(pmsProductAttributeValue);
            } else {
                productAttributeValueListUpdate.add(pmsProductAttributeValue);
            }
        }

        for (PmsProductAttributeValue pmsProductAttributeValue : productAttributeValueListOld) {
            if (productAttributeValueListNew.stream().noneMatch(item -> pmsProductAttributeValue.getId().equals(item.getId()))){
                productAttributeValueListDelete.add(pmsProductAttributeValue.getId());
            }
        }
        relateAndInsertList(productAttributeValueDao,productAttributeValueListInsert, id);
        relateAndUpdateList(productAttributeValueDao, productAttributeValueListUpdate);
        relateAndDeleteList(productAttributeValueDao,productAttributeValueListDelete);
        //关联专题
        List<CmsSubjectProductRelation> subjectProductRelationListOld = productParamOld.getSubjectProductRelationList();
        List<CmsSubjectProductRelation> subjectProductRelationListNew =  productParamNew.getSubjectProductRelationList();

        List<CmsSubjectProductRelation> subjectProductRelationListInsert = subjectProductRelationListNew.stream()
                .filter(item -> subjectProductRelationListOld.stream().noneMatch(item1 -> item1.getSubjectId().equals(item.getSubjectId())) )
                .distinct()
                .toList();
        List<CmsSubjectProductRelation> subjectProductRelationListDelete = subjectProductRelationListOld.stream()
                .filter(item -> subjectProductRelationListNew.stream().noneMatch(item1 -> item1.getSubjectId().equals(item.getSubjectId())) )
                .distinct()
                .toList();


        relateAndInsertList(subjectProductRelationDao,subjectProductRelationListInsert, id);
        relateAndDeleteList(subjectProductRelationDao,subjectProductRelationListDelete.stream().map(CmsSubjectProductRelation::getId).collect(Collectors.toList()));
        //关联优选

        List<CmsPrefrenceAreaProductRelation> prefrenceAreaProductRelationListOld = productParamOld.getPrefrenceAreaProductRelationList();
        List<CmsPrefrenceAreaProductRelation> prefrenceAreaProductRelationListNew = productParamNew.getPrefrenceAreaProductRelationList();

        List<CmsPrefrenceAreaProductRelation> prefrenceAreaProductRelationListInsert=   prefrenceAreaProductRelationListNew.stream()
                .filter(item -> prefrenceAreaProductRelationListOld.stream().noneMatch(item1 -> item1.getPrefrenceAreaId().equals(item.getPrefrenceAreaId())) )
                .distinct()
                .toList();

        List<CmsPrefrenceAreaProductRelation> prefrenceAreaProductRelationListDelete =   prefrenceAreaProductRelationListOld.stream()
                .filter(item -> prefrenceAreaProductRelationListNew.stream().noneMatch(item1 -> item1.getPrefrenceAreaId().equals(item.getPrefrenceAreaId())) )
                .distinct()
                .toList();


        relateAndInsertList(prefrenceAreaProductRelationDao,prefrenceAreaProductRelationListInsert, id);
        relateAndDeleteList(prefrenceAreaProductRelationDao,prefrenceAreaProductRelationListDelete.stream().map(CmsPrefrenceAreaProductRelation::getId).collect(Collectors.toList()));

        count = 1;
        return count;
    }

    @LogRecord(success = "更新了商品信息{_DIFF{#productParamOld, #productParamNew}}",
            type = "{{T(com.macro.mall.common.constant.Constant.OperationRecordConstant).TYPE_GOODS_INFO}}", subType = "{{T(com.macro.mall.common.constant.Constant.OperationRecordConstant).SUB_TYPE_GOODS_INFO_UPDATE}}", bizNo = "{{#productParamOld.id}}",
            extra = "{{T(cn.hutool.json.JSONUtil).toJsonStr(#productParamNew)}}")
    @Override
    public void diff(PmsProductParam productParamOld, PmsProductParam productParamNew) {
    }

    private void handleUpdateSkuStockList(Long id, PmsProductParam productParamNew) {
        //当前的sku信息
        List<PmsSkuStock> currSkuList = productParamNew.getSkuStockList();
        //当前没有sku直接删除
        if (CollUtil.isEmpty(currSkuList)) {
            PmsSkuStockExample skuStockExample = new PmsSkuStockExample();
            skuStockExample.createCriteria().andProductIdEqualTo(id);
            skuStockMapper.deleteByExample(skuStockExample);
            return;
        }
        //获取初始sku信息
        PmsSkuStockExample skuStockExample = new PmsSkuStockExample();
        skuStockExample.createCriteria().andProductIdEqualTo(id).andIsDeleteEqualTo(0l);
        List<PmsSkuStock> oriStuList = skuStockMapper.selectByExample(skuStockExample);
        //获取新增sku信息
        List<PmsSkuStock> insertSkuList = currSkuList.stream().filter(item -> item.getId() == null).collect(Collectors.toList());
        //获取需要更新的sku信息
        List<PmsSkuStock> updateSkuList = currSkuList.stream().filter(item -> item.getId() != null).collect(Collectors.toList());
        List<String> updateSkuIds = updateSkuList.stream().map(PmsSkuStock::getId).collect(Collectors.toList());
        //获取需要删除的sku信息
        List<PmsSkuStock> removeSkuList = oriStuList.stream().filter(item -> !updateSkuIds.contains(item.getId())).collect(Collectors.toList());
        handleSkuStockCode(insertSkuList, id);
        handleSkuStockCode(updateSkuList, id);
        //新增sku
        if (CollUtil.isNotEmpty(insertSkuList)) {
            relateAndInsertList(skuStockDao, insertSkuList, id);
        }
        //删除sku
        if (CollUtil.isNotEmpty(removeSkuList)) {
            List<String> removeSkuIds = removeSkuList.stream().map(PmsSkuStock::getId).collect(Collectors.toList());
            PmsSkuStockExample removeExample = new PmsSkuStockExample();
            removeExample.createCriteria().andIdIn(removeSkuIds);
            skuStockMapper.deleteByExample(removeExample);
        }
        //修改sku
        if (CollUtil.isNotEmpty(updateSkuList)) {
            for (PmsSkuStock pmsSkuStock : updateSkuList) {
                skuStockMapper.updateByPrimaryKeySelective(pmsSkuStock);
            }
        }

    }

    @Override
    public List<PmsProduct> list(PmsProductQueryParam productQueryParam, Integer pageSize, Integer pageNum) {
        PageHelper.startPage(pageNum, pageSize);
        PmsProductExample productExample = new PmsProductExample();
        PmsProductExample.Criteria criteria = productExample.createCriteria();
        if (productQueryParam.getPublishStatus() != null) {
            criteria.andPublishStatusEqualTo(productQueryParam.getPublishStatus());
        }
        if (productQueryParam.getVerifyStatus() != null) {
            criteria.andVerifyStatusEqualTo(productQueryParam.getVerifyStatus());
        }
        if (!StringUtils.isEmpty(productQueryParam.getKeyword())) {
            criteria.andNameLike("%" + productQueryParam.getKeyword() + "%");
        }
        if (!StringUtils.isEmpty(productQueryParam.getProductSn())) {
            criteria.andProductSnEqualTo(productQueryParam.getProductSn());
        }
        if (productQueryParam.getBrandId() != null) {
            criteria.andBrandIdEqualTo(productQueryParam.getBrandId());
        }
        if (productQueryParam.getProductCategoryId() != null) {
            criteria.andProductCategoryIdEqualTo(productQueryParam.getProductCategoryId());
        }
        criteria.andIsDeleteEqualTo(0L);
        return productMapper.selectByExample(productExample);
    }

    @Override
    public int updateVerifyStatus(List<Long> ids, Integer verifyStatus, String detail) {
        PmsProduct product = new PmsProduct();
        product.setVerifyStatus(verifyStatus);
        PmsProductExample example = new PmsProductExample();
        example.createCriteria().andIdIn(ids);
        List<PmsProductVertifyRecord> list = new ArrayList<>();
        int count = productMapper.updateByExampleSelective(product, example);
        //修改完审核状态后插入审核记录
        for (Long id : ids) {
            PmsProductVertifyRecord record = new PmsProductVertifyRecord();
            record.setProductId(id);
            record.setCreateTime(new Date());
            record.setDetail(detail);
            record.setStatus(verifyStatus);
            record.setVertifyMan("test");
            list.add(record);
        }
        productVertifyRecordDao.insertList(list);
        return count;
    }

    @Override
    public int updatePublishStatus(List<Long> ids, Integer publishStatus) {
        PmsProduct record = new PmsProduct();
        record.setPublishStatus(publishStatus);
        PmsProductExample example = new PmsProductExample();
        example.createCriteria().andIdIn(ids);
        return productMapper.updateByExampleSelective(record, example);
    }

    @Override
    public int updateRecommendStatus(List<Long> ids, Integer recommendStatus) {
        PmsProduct record = new PmsProduct();
        record.setRecommandStatus(recommendStatus);
        PmsProductExample example = new PmsProductExample();
        example.createCriteria().andIdIn(ids);
        return productMapper.updateByExampleSelective(record, example);
    }

    @Override
    public int updateNewStatus(List<Long> ids, Integer newStatus) {
        PmsProduct record = new PmsProduct();
        record.setNewStatus(newStatus);
        PmsProductExample example = new PmsProductExample();
        example.createCriteria().andIdIn(ids);
        return productMapper.updateByExampleSelective(record, example);
    }

    @Override
    public int updateDeleteStatus(List<Long> ids, Integer deleteStatus) {
        PmsProduct record = new PmsProduct();
     //   record.setDeleteStatus(deleteStatus);
        PmsProductExample example = new PmsProductExample();
        example.createCriteria().andIdIn(ids);
        return productMapper.deleteByExample( example);
    }

    @Override
    public List<PmsProduct> list(String keyword) {
        PmsProductExample productExample = new PmsProductExample();
        PmsProductExample.Criteria criteria = productExample.createCriteria();
        if (!StringUtils.isEmpty(keyword)) {
            criteria.andNameLike("%" + keyword + "%");
            productExample.or().andProductSnLike("%" + keyword + "%");
        }
        criteria.andIsDeleteEqualTo(0L);
        return productMapper.selectByExample(productExample);
    }

    @Override
    public HomeCommodityInfo getHomeCommodityInfo() {
        HomeCommodityInfo homeCommodityInfo = new HomeCommodityInfo();
        CompletableFuture takenOffTheShelves = CompletableFuture.runAsync(() -> {
            PmsProductQueryParam productQueryParam = new PmsProductQueryParam();
            productQueryParam.setPublishStatus(0);
            //'上架状态：0->下架；1->上架'
            homeCommodityInfo.setTakenOffTheShelvesNum(productMapper.selectCountByExample(productQueryParam));
        });

        CompletableFuture shelves = CompletableFuture.runAsync(() -> {
            PmsProductQueryParam productQueryParam = new PmsProductQueryParam();
            productQueryParam.setPublishStatus(1);
            //'上架状态：0->下架；1->上架'
            homeCommodityInfo.setShelvesNum(productMapper.selectCountByExample(productQueryParam));
        });

        CompletableFuture inventoryAlarms = CompletableFuture.runAsync(() -> {
            PmsProductQueryParam productQueryParam = new PmsProductQueryParam();
            productQueryParam.setPublishStatus(1);
            productQueryParam.setCheckStock(true);
            //'上架状态：0->下架；1->上架'
            homeCommodityInfo.setInventoryAlarmsNum(productMapper.selectCountByExample(productQueryParam));
        });

        CompletableFuture allCommodity = CompletableFuture.runAsync(() -> {
            PmsProductQueryParam productQueryParam = new PmsProductQueryParam();
            homeCommodityInfo.setAllCommodityNum(productMapper.selectCountByExample(productQueryParam));
        });
        takenOffTheShelves.join();
        shelves.join();
        inventoryAlarms.join();
        allCommodity.join();

        return homeCommodityInfo;
    }


    /**
     * 建立和插入关系表操作
     *
     * @param dao       可以操作的dao
     * @param dataList  要插入的数据
     * @param productId 建立关系的id
     */
    private void relateAndInsertList(Object dao, List dataList, Long productId) {
        try {
            if (CollectionUtils.isEmpty(dataList)) return;
            for (Object item : dataList) {
                Method setId = item.getClass().getMethod("setId", String.class);
                setId.invoke(item, (String) null);
                Method setProductId = item.getClass().getMethod("setProductId", Long.class);
                setProductId.invoke(item, productId);
            }
            Method insertList = dao.getClass().getMethod("insertList", List.class);
            insertList.invoke(dao, dataList);
        } catch (Exception e) {
            String rootCauseMessage = ExceptionUtils.getRootCauseMessage(e);
            LOGGER.warn("创建产品出错:{}", rootCauseMessage);
            throw new RuntimeException(rootCauseMessage);
        }
    }

    /**
     * 建立和更新关系表操作
     *
     * @param dao       可以操作的dao
     * @param dataList  要插入的数据
     */
    private void relateAndUpdateList(Object dao, List dataList) {
        try {
            if (CollectionUtils.isEmpty(dataList)) return;
            Method insertList = dao.getClass().getMethod("updateList", List.class);
            insertList.invoke(dao, dataList);
        } catch (Exception e) {
            String rootCauseMessage = ExceptionUtils.getRootCauseMessage(e);
            LOGGER.warn("创建产品出错:{}", rootCauseMessage);
            throw new RuntimeException(rootCauseMessage);
        }
    }

    /**
     * 建立和删除关系表操作
     *
     * @param dao       可以操作的dao
     * @param ids  要删除数据的id
     */
    private void relateAndDeleteList(Object dao, List<String> ids) {
        try {
            if (CollectionUtils.isEmpty(ids)) return;
            Method insertList = dao.getClass().getMethod("deleteList", List.class);
            insertList.invoke(dao, ids);
        } catch (Exception e) {
            String rootCauseMessage = ExceptionUtils.getRootCauseMessage(e);
            LOGGER.warn("创建产品出错:{}", rootCauseMessage);
            throw new RuntimeException(rootCauseMessage);
        }
    }


}
